﻿module VirtualCity.Setup.Agents

open Casanova
open Casanova.Utilities
open Casanova.Core
open Casanova.Coroutines
open Casanova.Game
open Casanova.Input
open Casanova.Math
open Casanova.Drawing
open VirtualCity
open VirtualCity.Scripts
open VirtualCity.Initialization
open VirtualCity.World
open VirtualCity.CityDescription
open VirtualCity.City
open VirtualCity.Rendering
open VirtualCity.PlanDescription
open VirtualCity.Scripts.Planner
open Casanova.StandardLibrary.Core
open Casanova.StandardLibrary.Physics


let create_agents num_agents (world:World) = 
  let num_homes = world.City.Buildings |> Seq.filter (fun b -> (!b.Caption.String).Contains("Home")) |> Seq.length
  let workplaces = world.City.Buildings |> Seq.filter (fun b -> !b.Items |> Seq.exists (fun i -> i.UseEffects |> Seq.exists (fun use_effect -> use_effect.MoneyGained > 0.0f<eur>))) |> Seq.toList
  let num_agents = min num_homes num_agents
  [
    for i,home in world.City.Buildings |> Seq.filter (fun b -> (!b.Caption.String).Contains("Home")) |> Seq.mapi (fun x y -> x,y) |> Seq.take num_agents do
      let workplaces = workplaces |> List.sortBy (fun wp -> Vector2.Distance(wp.Base.Position, home.Base.Position)) 
      let workplaces = workplaces |> Seq.take (max 1 (workplaces.Length / 4)) |> Seq.toList
      let work = workplaces |> List.RandomElement
      let agent = 
        let plan =
          {
            PlanDescription.Steps = []
          }
        {
          Name          = "George" + (i+1).ToString()
          Visual        = DrawableSprite.Create(world.Layers.Agents, Vector2.Zero, Vector2.One * 0.2f, @"Characters\man", Color.Azure)
          VisualOffset  = Vector2.Create(random_range -10.0f 10.0f, random_range -10.0f 10.0f) * 2.0f
          Physical      = PhysicalEntity.Create(home.Base.Position, 0.0f<m/s>)
          Home          = ref home
          Work          = ref work
          Stats         = Rule.Create(fun () -> Stats.One)
          Money         = var 20.0f<eur>
          ActivePlan    = var plan
          CurrentAction = var ""
          Selected      = var false
          DebugLog      = var ""
          StatsIdleMask = var Stats.One
        }
      world.City.Agents := agent :: !world.City.Agents
      yield co{
              do! wait (random_range 600.0f<s> 1800.0f<s>)
              let rec agent_planner() =
                co{
                  if (!agent.Stats).VitalMin <= 0.0f then
                    printf "Agent %s died with stats %s. His plan was \n%s\n." agent.Name ((!agent.Stats).ToString()) ((!agent.ActivePlan).ToString())
//                      agent.Stats := !agent.Stats + Stats.One
                  else
                    do! Planner.create_plan world.City agent
                    let! res = PlanExecutor.follow_plan true false world.City agent
                    do! yield_
                    do! agent_planner()
                }
              do! agent_planner()
            }
  ]
